﻿using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Xcj.Mes.DataBase.Interface;
using Xcj.Mes.WholeLine.DataBase.Common;
using Xcj.Mes.WholeLine.DataBase.Context;
using Xcj.Mes.WholeLine.DataBase.Entity;

namespace Xcj.Mes.DataBase.Service
{
    public class BaseService<T> : IBaseService<T> where T : BaseEntity, new()//这个类的定义表示一个通用的服务类 BaseService<T>，它实现了 IBaseService<T> 接口，并且可以操作 T 类型的对象。同时，它要求 T 类型必须是 BaseEntity 类型的子类，并且具有一个无参数的公共构造函数。
    {
        protected DbContext dbContext = SQLServerContext.GetInstance();

        public virtual void Dispose()
        {
            try
            {
                dbContext?.Database.CloseConnection();
                dbContext?.Dispose();
            }
            catch { }
        }

        //这段代码的目的是向数据上下文中添加实体对象，并根据需要选择是否保存更改。
        public virtual void Add(T Entity, bool IsSave = true)
        {
            if (dbContext == null)
                return;
            try
            {
                //DataContext.Configuration.ValidateOnSaveEnabled = false;
                dbContext.Set<T>().Add(Entity);
                //DataContext.Configuration.ValidateOnSaveEnabled = true;
                if (IsSave) Save();
            }
            catch { }
        }

        //这段代码的目的是返回数据上下文中与泛型类型T对应的实体对象的所有记录，并且这些记录不会被数据上下文跟踪。这可以用于执行只读操作或者不需要对实体对象进行更改跟踪的情况。
        public virtual IQueryable<T> All()
        {
            try
            {
                return dbContext?.Set<T>()?.AsNoTracking();
            }
            catch { }
            return null;
        }

        public virtual void Del(T Entity, bool IsSave = true)
        {
            if (dbContext == null)
                return;
            try
            {
                //dbContext.Configuration.ValidateOnSaveEnabled = false;
                dbContext.Entry(Entity).State = EntityState.Deleted;
                //dbContext.Configuration.ValidateOnSaveEnabled = true;
                if (IsSave) Save();
            }
            catch { }
        }

        public virtual void KeepLastData(int keepCount = 1000)  // 保留最近数据1000条
        {
            try
            {
                string sType = typeof(T).ToString();
                sType = sType.Substring(sType.LastIndexOf(".") + 1) + "s";

                if (keepCount <= 0)
                {
                    // 清除所有数据
                    // 开始事务
                    using (var transaction = dbContext?.Database?.BeginTransaction())
                    {
                        if (transaction == null)
                            return;

                        try
                        {
                            // 执行数据库操作
                            // 例如：使用DbCommand对象执行SQL命令
                            //dbContext?.Database?.ExecuteSql($"TRUNCATE TABLE {sType} ");
                            dbContext?.Database?.ExecuteSqlRaw($"TRUNCATE TABLE {sType} ");

                            // 提交事务
                            dbContext?.Database?.CommitTransaction();
                        }
                        catch // (Exception ex)
                        {
                            // 发生错误，回滚事务
                            dbContext?.Database?.RollbackTransaction();

                            // 处理异常
                            //throw;
                        }
                    }
                }
                else
                {
                    var datas = All()?.OrderByDescending(o => o.CreateTime).Take(keepCount)?.ToList();
                    if (datas?.Count() >= keepCount)
                    {
                        using (var transaction = dbContext?.Database?.BeginTransaction())
                        {
                            if (transaction == null)
                                return;

                            try
                            {
                                // 执行数据库操作
                                // 例如：使用DbCommand对象执行SQL命令
                                //dbContext?.Database?.ExecuteSql($"DELETE FROM {sType} WHERE ID <= {datas[datas.Count() - 1].ID}");
                                dbContext?.Database?.ExecuteSqlRaw($"DELETE FROM {sType} WHERE ID <= {datas[datas.Count() - 1].ID}");

                                // 提交事务
                                dbContext?.Database?.CommitTransaction();
                            }
                            catch // (Exception ex)
                            {
                                // 发生错误，回滚事务
                                dbContext?.Database?.RollbackTransaction();

                                // 处理异常
                                //throw;
                            }
                        }
                    }
                }
            }
            catch { }
        }

        //总体而言，该方法的作用是编辑实体对象，并根据需要选择是否保存更改。在编辑之前，它临时启用了实体验证，以避免在保存更改时触发验证错误。
        public virtual void Edit(T Entity, bool IsSave = true)
        {
            if(dbContext == null)
                return ;

            try
            {
                //dbContext.Configuration.ValidateOnSaveEnabled = false;
                dbContext.Entry(Entity).State = EntityState.Modified;
                //dbContext.Configuration.ValidateOnSaveEnabled = true;
                if (IsSave) Save();
            }
            catch { }
        }

        public virtual void Export(string ExportName, List<T> t, string SheetName = "数据导出")
        {

        }
/*
        public void Export(string ExportName, List<T> t, string SheetName = "数据导出")
        {
            try
            {
                IWorkbook wBook = null;//代码声明了一个名为"wBook"的变量，并将其初始化为null。

                if (Path.GetExtension(ExportName).ToLower() != ".xlsx")//使用Path.GetExtension(ExportName)方法获取导出文件名的扩展名，并使用ToLower()方法将其转换为小写字母。然后，使用条件语句if来检查扩展名是否不是".xlsx"。
                {
                    wBook = new HSSFWorkbook();//如果不是，表示文件不是Excel文件，因此创建一个HSSFWorkbook对象，并将其赋值给"wBook"变量。
                }
                else
                {
                    wBook = new XSSFWorkbook();//如果扩展名是".xlsx"，则表示文件是Excel文件，因此创建一个XSSFWorkbook对象，并将其赋值给"wBook"变量。
                }

                ISheet Sheet = wBook.CreateSheet(SheetName);

                // 添加表头
                var Pros = typeof(T).GetProperties();
                IRow Row = Sheet.CreateRow(0);
                int Index = 0;

                foreach (PropertyInfo pProp in Pros)
                {
                    string Alias = AliasAttribute(pProp);
                    if (!string.IsNullOrEmpty(Alias))
                    {
                        ICell cell = Row.CreateCell(Index);
                        cell.SetCellType(CellType.String);
                        cell.SetCellValue(Alias);

                        int Count = Encoding.UTF8.GetBytes(Alias).Length;
                        Sheet.SetColumnWidth(Index, Count * 500);

                        Index++;
                    }
                }

                // 添加数据
                for (int i = 0; i < t.Count; i++)
                {
                    Index = 0;
                    Row = Sheet.CreateRow(i + 1);
                    foreach (PropertyInfo pProp in Pros)
                    {
                        string Alias = AliasAttribute(pProp);
                        if (!string.IsNullOrEmpty(Alias))
                        {
                            object value = pProp.GetValue(t[i], null);
                            if(value != null)
                            {
                                ICell cell = Row.CreateCell(Index);
                                SetCellValue(cell, pProp, value, wBook);
                                Index++;
                            }
                        }
                    }
                }

                // 写入 
                using (MemoryStream mStream = new MemoryStream())//代码使用MemoryStream类创建一个名为"mStream"的内存流对象。MemoryStream类用于在内存中创建一个可承载数据的流。
                {
                    wBook.Write(mStream, true);//通过调用wBook.Write(mStream, true)方法，将工作簿对象中的数据写入到"mStream"内存流中。第二个参数true表示要将工作簿中的数据写入到内存流中，保留原有的格式。
                    using (FileStream FStream = new FileStream(ExportName, FileMode.Create, FileAccess.Write))//代码使用FileStream类创建一个名为"FStream"的文件流对象。FileStream类用于在磁盘上创建、读取或写入文件。 //在另一个using语句块中，通过调用new FileStream(ExportName, FileMode.Create, FileAccess.Write)来创建一个新的文件流对象。"ExportName"是一个参数，表示要创建的文件的名称和路径。FileMode.Create指定如果文件不存在，则创建一个新文件；FileAccess.Write指定可以写入文件的访问权限。
                    {
                        byte[] DataByte = mStream.ToArray();//代码将内存流中的数据转换为字节数组，通过调用mStream.ToArray()方法，并将结果赋值给名为"DataByte"的字节数组变量。
                        FStream.Write(DataByte, 0, DataByte.Length);//使用文件流对象"FStream"调用FStream.Write(DataByte, 0, DataByte.Length)方法，将字节数组中的数据写入到文件中。第一个参数是要写入的字节数组，第二个参数是写入的起始位置（通常为0），第三个参数是要写入的字节数。
                        FStream.Flush();//通过调用FStream.Flush()方法，确保将所有缓冲区中的数据写入到文件中，并释放文件流资源。
                    }
                }
            }
            catch //(Exception ex)
            {
                //throw ex;
            }
        }

        private void SetCellValue(ICell iCell, PropertyInfo pType, object oValue, IWorkbook wBook)
        {
            string dataType = pType.PropertyType.FullName;
            try
            {
                switch (dataType)
                {
                    case "System.Guid":
                        iCell.SetCellValue(Convert.ToString(oValue));
                        break;
                    case "System.String"://字符串类型
                        iCell.SetCellValue(Convert.ToString(oValue));
                        break;
                    case "System.DateTime"://日期类型
                        ICellStyle cellDateStyle = wBook.CreateCellStyle();
                        IDataFormat format = wBook.CreateDataFormat();
                        cellDateStyle.DataFormat = format.GetFormat("yyyy-MM-dd HH:mm:ss");//yyyy-mm-dd hh:mm:ss
                        iCell.CellStyle = cellDateStyle;
                        iCell.SetCellValue(Convert.ToDateTime(oValue));
                        break;
                    case "System.Boolean"://布尔型
                        iCell.SetCellValue(Convert.ToBoolean(oValue));
                        break;
                    case "System.Int16"://整型
                    case "System.Int32":
                    case "System.Int64":
                    case "System.Byte":
                        iCell.SetCellValue(Convert.ToUInt64(oValue));
                        break;
                    case "System.Single":
                    case "System.Decimal"://浮点型
                    case "System.Double":
                        iCell.SetCellValue(Convert.ToDouble(oValue));
                        break;
                    case "System.DBNull"://空值处理
                        iCell.SetCellValue("");
                        break;
                    case "System.Nullable"://空值处理
                        iCell.SetCellValue("");
                        break;
                    default:
                        iCell.SetCellValue("");
                        break;
                        //throw (new Exception(dataType + "：类型数据无法处理!"));
                }
            }
            catch { }
        }
*/
        private string AliasAttribute(PropertyInfo pInfo)
        {
            var Attributes = pInfo.GetCustomAttributes(typeof(AliasAttribute), false);
            AliasAttribute type = null;
            foreach (var o in Attributes)
            {
                if (o is AliasAttribute)
                {
                    type = o as AliasAttribute;
                }
            }

            return type?.Alias;
        }

        public virtual T One(Int64 ID)
        {
            try
            {
                return All()?.First(o => o.ID == ID);
            }
            catch { }

            return default(T);
        }

        //这个方法的作用就是将对数据库进行的更改保存到实际的数据库中。调用这个方法将会触发对实体对象的更改操作，并将这些更改持久化到数据库中。
        public virtual void Save()
        {
            try
            {
                dbContext?.SaveChanges();
            }
            catch { }
        }
    }
}
